﻿using System;
using System.Collections.Generic;
using System.Windows.Controls;
using TweetStreamer;
using System.Threading;
using System.Collections.ObjectModel;

namespace MSDNFlashRTRIAExample
{
    public partial class MainPage : UserControl
    {
        private const int AVG_RATE_VALUES = 20;

        private ObservableCollection<IStatusMessage> _messages = new ObservableCollection<IStatusMessage>();
        private ObservableCollection<ConnectionInformation> _connectionStatus = new ObservableCollection<ConnectionInformation>();

        Connection _twitterConnection;
        Thread _connectionThread;

        Queue<float> _dataTransferRates = new Queue<float>();

        /// <summary>
        /// Only display a fixed number of messages in the Grid.
        /// </summary>
        private int MAX_DISPLAYED_MESSAGES = 300;

        public MainPage()
        {
            InitializeComponent();

            _twitterConnection = new Connection();
            _twitterConnection.ConnectionStatusChanged += new Connection.OnConnectionStatusChangedEventHandler(twitterConnection_ConnectionStatusChanged);
            _twitterConnection.StatusMessageReceived +=
                new Connection.OnStatusMessageReceivedEventHandler(twitterConnection_StatusMessageReceived);
            _twitterConnection.DataTransferRateChanged += new Connection.OnDataTransferRateChangedHandler(_twitterConnection_DataTransferRateChanged);

            Tweets.ItemsSource = _messages;
            ConnectionStatusMessages.ItemsSource = _connectionStatus;

            _connectionThread = new Thread(StartConnection);
            _connectionThread.IsBackground = true;
            _connectionThread.Start();
        }

        void _twitterConnection_DataTransferRateChanged(object sender, IDataTransferRateChangeEventArgs args)
        {
            lock (_dataTransferRates)
            {
                _dataTransferRates.Enqueue(args.DataTranferRate);

                if (_dataTransferRates.Count >= AVG_RATE_VALUES)
                {

                    _dataTransferRates.Dequeue();
                }
            }

            decimal rate = GetAverageDataTransferRate();

            Dispatcher.BeginInvoke(() =>
                DataTransferRate.Text = (rate/1024).ToString() + "kbps"
            );
        }

        private decimal GetAverageDataTransferRate()
        {
            decimal value = 0;
            lock (_dataTransferRates)
            {
                foreach (decimal rate in this._dataTransferRates)
                {
                    value += rate;
                }
            }
            return value / AVG_RATE_VALUES;
        }

        /// <summary>
        /// Starts the connection to the Twitter streaming real-time data.
        /// </summary>
        void StartConnection()
        {
            _twitterConnection.Connect();
        }

        /// <summary>
        /// Status message received event handler.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        void twitterConnection_StatusMessageReceived(object sender, IStatusMessageReceivedEventArgs args)
        {
            Dispatcher.BeginInvoke(() =>
                AddMessage(args.Message)
            );            
        }

                /// <summary>
        /// Adds a message to the observable message list which updates the UI.
        /// </summary>
        /// <param name="message"></param>
        void AddMessage(IStatusMessage message)
        {
            ObservableCollection<IStatusMessage> messageList = ((ObservableCollection<IStatusMessage>)Tweets.ItemsSource);
            messageList.Insert(0, message);

            if (messageList.Count > MAX_DISPLAYED_MESSAGES)
            {
                messageList.RemoveAt(MAX_DISPLAYED_MESSAGES - 1);
            }
        }

        /// <summary>
        /// Connection status changed event handler.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        void twitterConnection_ConnectionStatusChanged(object sender, IConnectionStatusChangedEventArgs args)
        {
            Dispatcher.BeginInvoke(() =>
                    ((ObservableCollection<ConnectionInformation>)ConnectionStatusMessages.ItemsSource).Add(new ConnectionInformation(args.Status))
                );            

            if (args.Status == ConnectionStatus.Disconnected)
            {
                if (_connectionThread.ThreadState == ThreadState.Running)
                {
                    _connectionThread.Join();
                }
            }
        }

        /// <summary>
        /// Helper class to display connection information.
        /// </summary>
        private class ConnectionInformation
        {
            DateTime _eventTime;

            /// <summary>
            /// The time the connection information was generated.
            /// </summary>
            public string EventTime
            {
                get
                {
                    return _eventTime.ToString("g");
                }
            }

            private string _status;
            /// <summary>
            /// The status that the connection information represents.
            /// </summary>
            public string Status
            {
                get
                {
                    return this._status;
                }
            }

            /// <summary>
            /// Create a new instance of the ConnectionInformation class.
            /// </summary>
            /// <param name="status">The status of the connection information</param>
            public ConnectionInformation(ConnectionStatus status)
            {
                _status = status.ToString();
                _eventTime = DateTime.Now;
            }
        }
    }
}
